home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / HENSA / MATHS / PLPLOT / PLPLOT.ZIP / src / plline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-22  |  19.9 KB  |  823 lines

  1. /* $Id: plline.c,v 1.16 1994/07/22 15:54:37 furnish Exp $
  2.  * $Log: plline.c,v $
  3.  * Revision 1.16  1994/07/22  15:54:37  furnish
  4.  * Fix bug in selective segment draw capability of plpoly3().
  5.  *
  6.  * Revision 1.15  1994/07/20  10:38:57  mjl
  7.  * Fixed the error return on the two new routines.
  8.  *
  9.  * Revision 1.14  1994/07/20  06:09:22  mjl
  10.  * Changed syntax of the new 3d functions plline3() and plpoly3() to be more
  11.  * like plline(), and moved to this file.
  12.  *
  13.  * Revision 1.13  1994/06/30  18:22:11  mjl
  14.  * All core source files: made another pass to eliminate warnings when using
  15.  * gcc -Wall.  Lots of cleaning up: got rid of includes of math.h or string.h
  16.  * (now included by plplot.h), and other minor changes.  Now each file has
  17.  * global access to the plstream pointer via extern; many accessor functions
  18.  * eliminated as a result.
  19.  *
  20.  * Revision 1.12  1994/03/23  08:21:33  mjl
  21.  * Fiddled endlessly with plP_plfclp() trying to correctly clip polygons
  22.  * after a zoom (in TK driver).  Eventually realized it was resistant against
  23.  * quick hacks and got out the big gun: Foley, VanDam, et al (2nd ed), p 930:
  24.  * the Liang-Barsky Polygon Algorithm.  Unfortunately I don't have time to
  25.  * implement this right now; how about a volunteer?
  26.  *
  27.  * All external API source files: replaced call to plexit() on simple
  28.  * (recoverable) errors with simply printing the error message (via
  29.  * plabort()) and returning.  Should help avoid loss of computer time in some
  30.  * critical circumstances (during a long batch run, for example).
  31.  *
  32.  * Revision 1.11  1994/01/25  06:34:20  mjl
  33.  * Dashed line generation desuckified!  Should now run much faster on some
  34.  * architectures.  The previous loop used only conditionals, assignments, and
  35.  * integer adds at the cost of a huge number of iterations (basically testing
  36.  * each pixel).  The new method draws directly to the desired end of dash.
  37.  * Contributed by Wesley Ebisuzaki.
  38.  *
  39.  * Revision 1.10  1994/01/17  19:27:15  mjl
  40.  * Bug fix: changed declarations of xclp[] and yclp[] from static to local
  41.  * variables in plP_pllclp() and plP_plfclp(). plP_pllclp can call itself
  42.  * consequently it needs local variables. Fixed problem with dash line and
  43.  * orientation=1.  (Submitted by Wesley Ebisuzaki)
  44. */
  45.  
  46. /*    plline.c
  47.  
  48.     Routines dealing with line generation.
  49. */
  50.  
  51. #include "plplotP.h"
  52.  
  53. #define INSIDE(ix,iy) (BETW(ix,xmin,xmax) && BETW(iy,ymin,ymax))
  54.  
  55. static PLINT xline[PL_MAXPOLY], yline[PL_MAXPOLY];
  56.  
  57. static PLINT lastx = UNDEFINED, lasty = UNDEFINED;
  58.  
  59. /* Function prototypes */
  60.  
  61. /* Draws a polyline within the clip limits. */
  62.  
  63. static void
  64. pllclp(PLINT *x, PLINT *y, PLINT npts);
  65.  
  66. /* Get clipped endpoints */
  67.  
  68. static int
  69. clipline(PLINT *p_x1, PLINT *p_y1, PLINT *p_x2, PLINT *p_y2,
  70.      PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax);
  71.  
  72. /* General line-drawing routine.  Takes line styles into account. */
  73.  
  74. static void
  75. genlin(short *x, short *y, PLINT npts);
  76.  
  77. /* Draws a dashed line to the specified point from the previous one. */
  78.  
  79. static void
  80. grdashline(short *x, short *y);
  81.  
  82. /*----------------------------------------------------------------------*\
  83.  * void pljoin()
  84.  *
  85.  * Draws a line segment from (x1, y1) to (x2, y2).
  86. \*----------------------------------------------------------------------*/
  87.  
  88. void
  89. c_pljoin(PLFLT x1, PLFLT y1, PLFLT x2, PLFLT y2)
  90. {
  91.     plP_movwor(x1, y1);
  92.     plP_drawor(x2, y2);
  93. }
  94.  
  95. /*----------------------------------------------------------------------*\
  96.  * void plline()
  97.  *
  98.  * Draws line segments connecting a series of points.
  99. \*----------------------------------------------------------------------*/
  100.  
  101. void
  102. c_plline(PLINT n, PLFLT *x, PLFLT *y)
  103. {
  104.     if (plsc->level < 3) {
  105.     plabort("plline: Please set up window first");
  106.     return;
  107.     }
  108.     plP_drawor_poly(x, y, n);
  109. }
  110.  
  111. /*----------------------------------------------------------------------*\
  112.  * void plline3(n, x, y, z)
  113.  *
  114.  * Draws a line in 3 space.  You must first set up the viewport, the
  115.  * 2d viewing window (in world coordinates), and the 3d normalized
  116.  * coordinate box.  See x18c.c for more info.
  117. \*----------------------------------------------------------------------*/
  118.  
  119. void
  120. c_plline3(PLINT n, PLFLT *x, PLFLT *y, PLFLT *z)
  121. {
  122.     int i;
  123.     PLFLT u, v;
  124.  
  125.     if (plsc->level < 3) {
  126.     plabort("plline3: Please set up window first");
  127.     return;
  128.     }
  129.  
  130.     for( i=0; i < n; i++ ) {
  131.     u = plP_wcpcx(plP_w3wcx( x[i], y[i], z[i] ));
  132.     v = plP_wcpcy(plP_w3wcy( x[i], y[i], z[i] ));
  133.     if (i==0)
  134.         plP_movphy(u,v);
  135.     else
  136.         plP_draphy(u,v);
  137.     }
  138.     return;
  139. }
  140.  
  141. /*----------------------------------------------------------------------*\
  142.  * void plpoly3( n, x, y, z, draw )
  143.  *
  144.  * Draws a polygon in 3 space.  This differs from plline3() in that
  145.  * this attempts to determine if the polygon is viewable.  If the back
  146.  * of polygon is facing the viewer, then it isn't drawn.  If this
  147.  * isn't what you want, then use plline3 instead.
  148.  *
  149.  * n specifies the number of points.  They are assumed to be in a
  150.  * plane, and the directionality of the plane is determined from the
  151.  * first three points.  Additional points do not /have/ to lie on the
  152.  * plane defined by the first three, but if they do not, then the
  153.  * determiniation of visibility obviously can't be 100% accurate...
  154.  * So if you're 3 space polygons are too far from planar, consider
  155.  * breaking them into smaller polygons.  "3 points define a plane" :-).
  156.  *
  157.  * The directionality of the polygon is determined by assuming the
  158.  * points are laid out in clockwise order.  If you are drawing them in
  159.  * counter clockwise order, make n the negative of the number of
  160.  * points.
  161.  *
  162.  * BUGS:  If one of the first two segments is of zero length, or if
  163.  * they are colinear, the calculation of visibility has a 50/50 chance
  164.  * of being correct.  Avoid such situations :-).  See x18c for an
  165.  * example of this problem.  (Search for "20.1").
  166. \*----------------------------------------------------------------------*/
  167.  
  168. void
  169. c_plpoly3(PLINT n, PLFLT *x, PLFLT *y, PLFLT *z, PLINT *draw)
  170. {
  171.     int i, nn;
  172.     PLFLT u, v;
  173.     PLFLT u1, v1, u2, v2, u3, v3;
  174.     PLFLT c;
  175.  
  176.     if (plsc->level < 3) {
  177.     plabort("plpoly3: Please set up window first");
  178.     return;
  179.     }
  180.  
  181.     nn = abs(n);
  182.     if ( nn < 3 ) {
  183.     plabort("plpoly3: Must specify at least 3 points");
  184.     return;
  185.     }
  186.  
  187. /* Now figure out which side this is. */
  188.  
  189.     u1 = plP_wcpcx(plP_w3wcx( x[0], y[0], z[0] ));
  190.     v1 = plP_wcpcy(plP_w3wcy( x[0], y[0], z[0] ));
  191.  
  192.     u2 = plP_wcpcx(plP_w3wcx( x[1], y[1], z[1] ));
  193.     v2 = plP_wcpcy(plP_w3wcy( x[1], y[1], z[1] ));
  194.  
  195.     u3 = plP_wcpcx(plP_w3wcx( x[2], y[2], z[2] ));
  196.     v3 = plP_wcpcy(plP_w3wcy( x[2], y[2], z[2] ));
  197.  
  198.     c = (u1-u2)*(v3-v2)-(v1-v2)*(u3-u2);
  199.  
  200.     if ( c * n < 0. )
  201.     return;
  202.  
  203.     for( i=0; i < nn; i++ ) {
  204.     u = plP_wcpcx(plP_w3wcx( x[i], y[i], z[i] ));
  205.     v = plP_wcpcy(plP_w3wcy( x[i], y[i], z[i] ));
  206.     if (i==0)
  207.         plP_movphy(u,v);
  208.     else if (draw[i-1])
  209.         plP_draphy(u,v);
  210.     else
  211.         plP_movphy(u,v);
  212.     }
  213.  
  214.     return;
  215. }
  216.  
  217. /*----------------------------------------------------------------------*\
  218.  * void plstyl()
  219.  *
  220.  * Set up a new line style of "nms" elements, with mark and space
  221.  * lengths given by arrays "mark" and "space".
  222. \*----------------------------------------------------------------------*/
  223.  
  224. void
  225. c_plstyl(PLINT nms, PLINT *mark, PLINT *space)
  226. {
  227.     short int i;
  228.  
  229.     if (plsc->level < 1) {
  230.     plabort("plstyl: Please call plinit first");
  231.     return;
  232.     }
  233.     if ((nms < 0) || (nms > 10)) {
  234.     plabort("plstyl: Broken lines cannot have <0 or >10 elements");
  235.     return;
  236.     }
  237.     for (i = 0; i < nms; i++) {
  238.     if ((mark[i] < 0) || (space[i] < 0)) {
  239.         plabort("plstyl: Mark and space lengths must be > 0");
  240.         return;
  241.     }
  242.     }
  243.  
  244.     plsc->nms = nms;
  245.     for (i = 0; i < nms; i++) {
  246.     plsc->mark[i] = mark[i];
  247.     plsc->space[i] = space[i];
  248.     }
  249.  
  250.     plsc->curel = 0;
  251.     plsc->pendn = 1;
  252.     plsc->timecnt = 0;
  253.     plsc->alarm = nms > 0 ? mark[0] : 0;
  254. }
  255.  
  256. /*----------------------------------------------------------------------*\
  257.  * void plP_movphy()
  258.  *
  259.  * Move to physical coordinates (x,y).
  260. \*----------------------------------------------------------------------*/
  261.  
  262. void
  263. plP_movphy(PLINT x, PLINT y)
  264. {
  265.     plsc->currx = x;
  266.     plsc->curry = y;
  267. }
  268.  
  269. /*----------------------------------------------------------------------*\
  270.  * void plP_draphy()
  271.  *
  272.  * Draw to physical coordinates (x,y).
  273. \*----------------------------------------------------------------------*/
  274.  
  275. void
  276. plP_draphy(PLINT x, PLINT y)
  277. {
  278.     xline[0] = plsc->currx;
  279.     xline[1] = x;
  280.     yline[0] = plsc->curry;
  281.     yline[1] = y;
  282.  
  283.     pllclp(xline, yline, 2);
  284. }
  285.  
  286. /*----------------------------------------------------------------------*\
  287.  * void plP_movwor()
  288.  *
  289.  * Move to world coordinates (x,y).
  290. \*----------------------------------------------------------------------*/
  291.  
  292. void
  293. plP_movwor(PLFLT x, PLFLT y)
  294. {
  295.     plsc->currx = plP_wcpcx(x);
  296.     plsc->curry = plP_wcpcy(y);
  297. }
  298.  
  299. /*----------------------------------------------------------------------*\
  300.  * void plP_drawor()
  301.  *
  302.  * Draw to world coordinates (x,y).
  303. \*----------------------------------------------------------------------*/
  304.  
  305. void
  306. plP_drawor(PLFLT x, PLFLT y)
  307. {
  308.     xline[0] = plsc->currx;
  309.     xline[1] = plP_wcpcx(x);
  310.     yline[0] = plsc->curry;
  311.     yline[1] = plP_wcpcy(y);
  312.  
  313.     pllclp(xline, yline, 2);
  314. }
  315.  
  316. /*----------------------------------------------------------------------*\
  317.  * void plP_draphy_poly()
  318.  *
  319.  * Draw polyline in physical coordinates.
  320.  * Need to draw buffers in increments of (PL_MAXPOLY-1) since the
  321.  * last point must be repeated (for solid lines).
  322. \*----------------------------------------------------------------------*/
  323.  
  324. void
  325. plP_draphy_poly(PLINT *x, PLINT *y, PLINT n)
  326. {
  327.     PLINT i, j, ib, ilim;
  328.  
  329.     for (ib = 0; ib < n; ib += PL_MAXPOLY - 1) {
  330.     ilim = MIN(PL_MAXPOLY, n - ib);
  331.  
  332.     for (i = 0; i < ilim; i++) {
  333.         j = ib + i;
  334.         xline[i] = x[j];
  335.         yline[i] = y[j];
  336.     }
  337.     pllclp(xline, yline, ilim);
  338.     }
  339. }
  340.  
  341. /*----------------------------------------------------------------------*\
  342.  * void plP_drawor_poly()
  343.  *
  344.  * Draw polyline in world coordinates.
  345.  * Need to draw buffers in increments of (PL_MAXPOLY-1) since the
  346.  * last point must be repeated (for solid lines).
  347. \*----------------------------------------------------------------------*/
  348.  
  349. void
  350. plP_drawor_poly(PLFLT *x, PLFLT *y, PLINT n)
  351. {
  352.     PLINT i, j, ib, ilim;
  353.  
  354.     for (ib = 0; ib < n; ib += PL_MAXPOLY - 1) {
  355.     ilim = MIN(PL_MAXPOLY, n - ib);
  356.  
  357.     for (i = 0; i < ilim; i++) {
  358.         j = ib + i;
  359.         xline[i] = plP_wcpcx(x[j]);
  360.         yline[i] = plP_wcpcy(y[j]);
  361.     }
  362.     pllclp(xline, yline, ilim);
  363.     }
  364. }
  365.  
  366. /*----------------------------------------------------------------------*\
  367.  * void pllclp()
  368.  *
  369.  * Draws a polyline within the clip limits.
  370.  * Merely a front-end to plP_pllclp().
  371. \*----------------------------------------------------------------------*/
  372.  
  373. static void
  374. pllclp(PLINT *x, PLINT *y, PLINT npts)
  375. {
  376.     plP_pllclp(x, y, npts, plsc->clpxmi, plsc->clpxma,
  377.            plsc->clpymi, plsc->clpyma, genlin);
  378. }
  379.  
  380. /*----------------------------------------------------------------------*\
  381.  * void plP_pllclp()
  382.  *
  383.  * Draws a polyline within the clip limits.
  384. \*----------------------------------------------------------------------*/
  385.  
  386. void
  387. plP_pllclp(PLINT *x, PLINT *y, PLINT npts,
  388.        PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax, 
  389.        void (*draw) (short *, short *, PLINT))
  390. {
  391.     PLINT x1, x2, y1, y2;
  392.     PLINT i, iclp = 0;
  393.     short xclp[PL_MAXPOLY], yclp[PL_MAXPOLY];
  394.     int drawable;
  395.  
  396.     for (i = 0; i < npts - 1; i++) {
  397.     x1 = x[i];
  398.     x2 = x[i + 1];
  399.     y1 = y[i];
  400.     y2 = y[i + 1];
  401.  
  402.     drawable = (INSIDE(x1, y1) && INSIDE(x2, y2));
  403.     if ( ! drawable)
  404.         drawable = ! clipline(&x1, &y1, &x2, &y2, xmin, xmax, ymin, ymax);
  405.  
  406.     if (drawable) {
  407.  
  408. /* First point of polyline. */
  409.  
  410.         if (iclp == 0) {
  411.         xclp[iclp] = x1;
  412.         yclp[iclp] = y1;
  413.         iclp++;
  414.         xclp[iclp] = x2;
  415.         yclp[iclp] = y2;
  416.         }
  417.  
  418. /* Not first point.  Check if first point of this segment matches up to 
  419.    previous point, and if so, add it to the current polyline buffer. */
  420.  
  421.         else if (x1 == xclp[iclp] && y1 == yclp[iclp]) {
  422.         iclp++;
  423.         xclp[iclp] = x2;
  424.         yclp[iclp] = y2;
  425.         }
  426.  
  427. /* Otherwise it's time to start a new polyline */
  428.  
  429.         else {
  430.         if (iclp + 1 >= 2)
  431.             (*draw)(xclp, yclp, iclp + 1);
  432.         iclp = 0;
  433.         xclp[iclp] = x1;
  434.         yclp[iclp] = y1;
  435.         iclp++;
  436.         xclp[iclp] = x2;
  437.         yclp[iclp] = y2;
  438.         }
  439.     }
  440.     }
  441.  
  442. /* Handle remaining polyline */
  443.  
  444.     if (iclp + 1 >= 2)
  445.     (*draw)(xclp, yclp, iclp + 1);
  446.  
  447.     plsc->currx = x[npts-1];
  448.     plsc->curry = y[npts-1];
  449. }
  450.  
  451. /*----------------------------------------------------------------------*\
  452.  * void plP_plfclp()
  453.  *
  454.  * Fills a polygon within the clip limits.
  455. \*----------------------------------------------------------------------*/
  456.  
  457. void
  458. plP_plfclp(PLINT *x, PLINT *y, PLINT npts,
  459.        PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax, 
  460.        void (*draw) (short *, short *, PLINT))
  461. {
  462.     PLINT x1, x2, y1, y2;
  463.     PLINT i, j, iclp = -1;
  464.     short xclp[PL_MAXPOLY], yclp[PL_MAXPOLY];
  465.     int drawable;
  466.  
  467.     for (i = 0; i < npts - 1; i++) {
  468.     x1 = x[i];
  469.     x2 = x[i + 1];
  470.     y1 = y[i];
  471.     y2 = y[i + 1];
  472.  
  473.     drawable = (INSIDE(x1, y1) && INSIDE(x2, y2));
  474.     if ( ! drawable)
  475.         drawable = ! clipline(&x1, &y1, &x2, &y2, xmin, xmax, ymin, ymax);
  476.  
  477.     if (drawable) {
  478.  
  479. /* Not first point.  If first point of this segment matches up to the
  480.    previous point, just add it.  */
  481.  
  482.         if (iclp >= 0 && x1 == xclp[iclp] && y1 == yclp[iclp]) {
  483.         iclp++;
  484.         xclp[iclp] = x2;
  485.         yclp[iclp] = y2;
  486.         }
  487.  
  488. /* First point of polyline, OR . */
  489.  
  490. /* If not, we need to add both points, to connect the points in the
  491.  * polygon along the clip boundary.  If any of the previous points were
  492.  * outside one of the 4 corners, assume the corner was encircled and add
  493.  * it first. 
  494.  */
  495.         else {
  496.         iclp++;
  497.         xclp[iclp] = x1;
  498.         yclp[iclp] = y1;
  499.  
  500.         if ((x1 == xmin && y2 == ymin) ||
  501.             (x2 == xmin && y1 == ymin)) {
  502.             iclp++;
  503.             xclp[iclp] = xmin;
  504.             yclp[iclp] = ymin;
  505.         }
  506.         else if ((x1 == xmax && y2 == ymin) ||
  507.              (x2 == xmax && y1 == ymin)) {
  508.             iclp++;
  509.             xclp[iclp] = xmax;
  510.             yclp[iclp] = ymin;
  511.         }
  512.         else if ((x1 == xmax && y2 == ymax) ||
  513.              (x2 == xmax && y1 == ymax)) {
  514.             iclp++;
  515.             xclp[iclp] = xmax;
  516.             yclp[iclp] = ymax;
  517.         }
  518.         else if ((x1 == xmin && y2 == ymax) ||
  519.              (x2 == xmin && y1 == ymax)) {
  520.             iclp++;
  521.             xclp[iclp] = xmin;
  522.             yclp[iclp] = ymax;
  523.         }
  524. /*
  525.         for (j = 0; j < i; j++) {
  526.             if (x[j] < xmin && y[j] < ymin) {
  527.             break;
  528.             }
  529.             else if (x[j] < xmin && y[j] > ymax) {
  530.             iclp++;
  531.             xclp[iclp] = xmin;
  532.             yclp[iclp] = ymax;
  533.             break;
  534.             }
  535.             else if (x[j] > xmax && y[j] < ymin) {
  536.             iclp++;
  537.             xclp[iclp] = xmax;
  538.             yclp[iclp] = ymin;
  539.             break;
  540.             }
  541.             else if (x[j] > xmax && y[j] > ymax) {
  542.             iclp++;
  543.             xclp[iclp] = xmax;
  544.             yclp[iclp] = ymax;
  545.             break;
  546.             }
  547.         }
  548. */
  549.         iclp++;
  550.         xclp[iclp] = x2;
  551.         yclp[iclp] = y2;
  552.         }
  553.     }
  554.     }
  555.  
  556. /* Draw the sucker */
  557.  
  558.     if (iclp + 1 >= 2) {
  559.     if ((xclp[0] == xmin && yclp[iclp] == ymin) ||
  560.         (xclp[iclp] == xmin && yclp[0] == ymin)) {
  561.         iclp++;
  562.         xclp[iclp] = xmin;
  563.         yclp[iclp] = ymin;
  564.     }
  565.     else if ((xclp[0] == xmax && yclp[iclp] == ymin) ||
  566.          (xclp[iclp] == xmax && yclp[0] == ymin)) {
  567.         iclp++;
  568.         xclp[iclp] = xmax;
  569.         yclp[iclp] = ymin;
  570.     }
  571.     else if ((xclp[0] == xmax && yclp[iclp] == ymax) ||
  572.          (xclp[iclp] == xmax && yclp[0] == ymax)) {
  573.         iclp++;
  574.         xclp[iclp] = xmax;
  575.         yclp[iclp] = ymax;
  576.     }
  577.     else if ((xclp[0] == xmin && yclp[iclp] == ymax) ||
  578.          (xclp[iclp] == xmin && yclp[0] == ymax)) {
  579.         iclp++;
  580.         xclp[iclp] = xmin;
  581.         yclp[iclp] = ymax;
  582.     }
  583.     }
  584.     if (iclp + 1 >= 3) {
  585.     (*draw)(xclp, yclp, iclp + 1);
  586.     }
  587. }
  588.  
  589. /*----------------------------------------------------------------------*\
  590.  * int clipline()
  591.  *
  592.  * Get clipped endpoints
  593. \*----------------------------------------------------------------------*/
  594.  
  595. static int
  596. clipline(PLINT *p_x1, PLINT *p_y1, PLINT *p_x2, PLINT *p_y2,
  597.      PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax)
  598. {
  599.     PLINT t, dx, dy, flipx, flipy;
  600.     double dydx, dxdy;
  601.  
  602. /* If both points are outside clip region with no hope of intersection,
  603.    return with an error */
  604.  
  605.     if ((*p_x1 <= xmin && *p_x2 <= xmin) ||
  606.     (*p_x1 >= xmax && *p_x2 >= xmax) ||
  607.     (*p_y1 <= ymin && *p_y2 <= ymin) ||
  608.     (*p_y1 >= ymax && *p_y2 >= ymax))
  609.     return 1;
  610.  
  611.     flipx = 0;
  612.     flipy = 0;
  613.  
  614.     if (*p_x2 < *p_x1) {
  615.     *p_x1 = 2 * xmin - *p_x1;
  616.     *p_x2 = 2 * xmin - *p_x2;
  617.     xmax = 2 * xmin - xmax;
  618.     t = xmax;
  619.     xmax = xmin;
  620.     xmin = t;
  621.     flipx = 1;
  622.     }
  623.  
  624.     if (*p_y2 < *p_y1) {
  625.     *p_y1 = 2 * ymin - *p_y1;
  626.     *p_y2 = 2 * ymin - *p_y2;
  627.     ymax = 2 * ymin - ymax;
  628.     t = ymax;
  629.     ymax = ymin;
  630.     ymin = t;
  631.     flipy = 1;
  632.     }
  633.  
  634.     dx = *p_x2 - *p_x1;
  635.     dy = *p_y2 - *p_y1;
  636.  
  637.     if (dx != 0 && dy != 0) {
  638.     dydx = (double) dy / (double) dx;
  639.     dxdy = 1./ dydx;
  640.     }
  641.  
  642.     if (*p_x1 < xmin) {
  643.     if (dx != 0 && dy != 0)
  644.         *p_y1 = *p_y1 + ROUND((xmin - *p_x1) * dydx);
  645.     *p_x1 = xmin;
  646.     }
  647.  
  648.     if (*p_y1 < ymin) {
  649.     if (dx != 0 && dy != 0)
  650.         *p_x1 = *p_x1 + ROUND((ymin - *p_y1) * dxdy);
  651.     *p_y1 = ymin;
  652.     }
  653.  
  654.     if (*p_x1 >= xmax || *p_y1 >= ymax)
  655.     return 1;
  656.  
  657.     if (*p_y2 > ymax) {
  658.     if (dx != 0 && dy != 0)
  659.         *p_x2 = *p_x2 - ROUND((*p_y2 - ymax) * dxdy);
  660.     *p_y2 = ymax;
  661.     }
  662.  
  663.     if (*p_x2 > xmax) {
  664.     if (dx != 0 && dy != 0)
  665.         *p_y2 = *p_y2 - ROUND((*p_x2 - xmax) * dydx);
  666.     *p_x2 = xmax;
  667.     }
  668.  
  669.     if (flipx) {
  670.     *p_x1 = 2 * xmax - *p_x1;
  671.     *p_x2 = 2 * xmax - *p_x2;
  672.     }
  673.  
  674.     if (flipy) {
  675.     *p_y1 = 2 * ymax - *p_y1;
  676.     *p_y2 = 2 * ymax - *p_y2;
  677.     }
  678.  
  679.     return 0;
  680. }
  681.  
  682. /*----------------------------------------------------------------------*\
  683.  * void genlin()
  684.  *
  685.  * General line-drawing routine.  Takes line styles into account.
  686.  * If only 2 points are in the polyline, it is more efficient to use
  687.  * plP_line() rather than plP_polyline().
  688. \*----------------------------------------------------------------------*/
  689.  
  690. static void
  691. genlin(short *x, short *y, PLINT npts)
  692. {
  693. /* Check for solid line */
  694.  
  695.     if (plsc->nms == 0) {
  696.     if (npts== 2)
  697.         plP_line(x, y);
  698.     else
  699.         plP_polyline(x, y, npts);
  700.     }
  701.  
  702. /* Right now dashed lines don't use polyline capability -- this
  703.    should be improved */
  704.  
  705.     else {
  706.     PLINT i;
  707.     for (i = 0; i < npts - 1; i++) {
  708.         grdashline(x+i, y+i);
  709.     }
  710.     }
  711. }
  712.  
  713. /*----------------------------------------------------------------------*\
  714.  * void grdashline()
  715.  *
  716.  * Draws a dashed line to the specified point from the previous one.
  717. \*----------------------------------------------------------------------*/
  718.  
  719. static void
  720. grdashline(short *x, short *y)
  721. {
  722.     PLINT nx, ny, nxp, nyp, incr, temp;
  723.     PLINT modulo, dx, dy, i, xtmp, ytmp;
  724.     PLINT tstep, pix_distance, j;
  725.     int loop_x;
  726.     short xl[2], yl[2];
  727.     double nxstep, nystep;
  728.  
  729. /* Check if pattern needs to be restarted */
  730.  
  731.     if (x[0] != lastx || y[0] != lasty) {
  732.     plsc->curel = 0;
  733.     plsc->pendn = 1;
  734.     plsc->timecnt = 0;
  735.     plsc->alarm = plsc->mark[0];
  736.     }
  737.  
  738.     lastx = xtmp = x[0];
  739.     lasty = ytmp = y[0];
  740.  
  741.     if (x[0] == x[1] && y[0] == y[1])
  742.     return;
  743.  
  744.     nx = x[1] - x[0];
  745.     dx = (nx > 0) ? 1 : -1;
  746.     nxp = ABS(nx);
  747.  
  748.     ny = y[1] - y[0];
  749.     dy = (ny > 0) ? 1 : -1;
  750.     nyp = ABS(ny);
  751.  
  752.     if (nyp > nxp) {
  753.     modulo = nyp;
  754.     incr = nxp;
  755.     loop_x = 0;
  756.     }
  757.     else {
  758.     modulo = nxp;
  759.     incr = nyp;
  760.     loop_x = 1;
  761.     }
  762.  
  763.     temp = modulo / 2;
  764.  
  765. /* Compute the timer step */
  766.  
  767.     nxstep = nxp * plsc->umx;
  768.     nystep = nyp * plsc->umy;
  769.     tstep = sqrt( nxstep * nxstep + nystep * nystep ) / modulo;
  770.     if (tstep < 1) tstep = 1;
  771.  
  772.     /* tstep is distance per pixel moved */
  773.  
  774.     i = 0;
  775.     while (i < modulo) {
  776.         pix_distance = (plsc->alarm - plsc->timecnt + tstep - 1) / tstep;
  777.     i += pix_distance;
  778.     if (i > modulo)
  779.         pix_distance -= (i - modulo);
  780.     plsc->timecnt += pix_distance * tstep;
  781.  
  782.     temp += pix_distance * incr;
  783.     j = temp / modulo;
  784.     temp = temp % modulo;
  785.  
  786.     if (loop_x) {
  787.         xtmp += pix_distance * dx;
  788.         ytmp += j * dy;
  789.     }
  790.     else {
  791.         xtmp += j * dx;
  792.         ytmp += pix_distance * dy;
  793.     }
  794.     if (plsc->pendn != 0) {
  795.         xl[0] = lastx;
  796.         yl[0] = lasty;
  797.         xl[1] = xtmp;
  798.         yl[1] = ytmp;
  799.         plP_line(xl, yl);
  800.     }
  801.  
  802. /* Update line style variables when alarm goes off */
  803.  
  804.     while (plsc->timecnt >= plsc->alarm) {
  805.         if (plsc->pendn != 0) {
  806.         plsc->pendn = 0;
  807.         plsc->timecnt -= plsc->alarm;
  808.         plsc->alarm = plsc->space[plsc->curel];
  809.         }
  810.         else {
  811.         plsc->pendn = 1;
  812.         plsc->timecnt -= plsc->alarm;
  813.         plsc->curel++;
  814.         if (plsc->curel >= plsc->nms)
  815.             plsc->curel = 0;
  816.         plsc->alarm = plsc->mark[plsc->curel];
  817.         }
  818.     }
  819.     lastx = xtmp;
  820.     lasty = ytmp;
  821.     }
  822. }
  823.